//! http3协议传输

mod common;

use common::{call_service::client_demo, declare_service::app::*};
use quic_rpc_utils::{
    QuinnConnector, QuinnEndpoint, QuinnListener, Result, configure_client, configure_server,
    gen_server_cert,
};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};

/// 构造一个仅供客户端使用的 QUIC 端点。
///
/// ## Args
///
/// - `server_certs`: 受信任证书列表。
fn make_client_endpoint(bind_addr: SocketAddr, server_certs: &[&[u8]]) -> Result<QuinnEndpoint> {
    let client_cfg = configure_client(server_certs)?;
    let mut endpoint = QuinnEndpoint::client(bind_addr)?;
    endpoint.set_default_client_config(client_cfg);
    Ok(endpoint)
}

/// 构造一个 QUIC 端点，配置为监听特定地址和端口上的传入连接。
///
/// ## Returns
///
/// - 传入的 QUIC 连接流
/// - 服务器证书序列化为 DER 格式
fn make_server_endpoint(bind_addr: SocketAddr) -> Result<(QuinnEndpoint, Vec<u8>)> {
    let (server_cert, private_key) = gen_server_cert(&["localhost"])?;
    let server_config = configure_server(0, server_cert.clone(), private_key)?;
    let endpoint = QuinnEndpoint::server(server_config, bind_addr)?;
    Ok((endpoint, server_cert))
}

#[tokio::main]
async fn main() -> Result<()> {
    let server_addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 9988));
    let (server, server_certs) = make_server_endpoint(server_addr)?;
    let client = make_client_endpoint("0.0.0.0:0".parse()?, &[&server_certs])?;
    let _server_conn = QuinnListener::new(server)?;
    let _client_conn = QuinnConnector::new(client, server_addr, "localhost".into());

    #[cfg(all(feature = "server", not(feature = "client")))]
    {
        use quic_rpc_utils::{RpcServer, run_server};
        let server = RpcServer::<AppService, _>::new(_server_conn);
        run_server(server).await
    }
    #[cfg(all(feature = "client", not(feature = "server")))]
    {
        use quic_rpc_utils::RpcClient;
        let client = RpcClient::<AppService, _>::new(_client_conn);
        client_demo(client).await?;
    }
    #[cfg(all(feature = "client", feature = "server"))]
    {
        use quic_rpc_utils::{RpcServer, run_server};
        let server = RpcServer::new(_server_conn.clone());
        tokio::spawn(run_server::<AppService, _>(server));

        use quic_rpc_utils::RpcClient;
        let client = RpcClient::new(_client_conn);
        client_demo(client.boxed()).await?;
    }

    Ok(())
}
